import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt


class MonteCarlo(object):
    """
    蒙特卡洛方法（随机抽样或统计试验方法）
    很大程度上取决于随机数生成器
    """
    @staticmethod
    def fruit_shop():
        """
        水果店

        每天出售水果，每份订单Y个单位，每个单位60美分利润，一天结束时，未售出的以每个单位40美分损失抛售，
        每天需要量服从均匀分布[80， 140]，问题：每天多少订单可以使得利润最大化

        销售量：s，需求量：d
        benifit = 0.6 * s if d >= s else 0.6 * d - 0.4 (s - d)
        :return:
        """
        # matplotlib中文显示方块
        mpl.rcParams['font.sans-serif'] = ['SimHei']  # 指定默认字体
        mpl.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题

        def get_benifit(d, s):
            return 0.6 * s if d >= s else 0.6 * d - 0.4 * (s - d)

        x = []
        y = []

        max_benifit = 0
        for s in range(20, 305):
            # 蒙特卡洛模拟:1000次区间均匀分布
            for i in range(1, 1000):
                # d = np.random.randint(10, 200)
                d = np.random.randint(80, 141)
                benifit = get_benifit(d, s)
                max_benifit = benifit if benifit > max_benifit else max_benifit

            x.append(s)
            # y.append(np.log(max_benifit))
            y.append(max_benifit)

        max_y = max(y)
        x_index = x[y.index(max_y)]
        print('x: {}, x_index: {}'.format(x[x_index], x_index))
        print('y: {}'.format(max_y))

        plt.plot(x, y)
        plt.xlabel('销售量')
        plt.ylabel('最大收益')
        plt.title('销售量与收益之间关系')
        plt.grid(True)

        plt.show()

    @staticmethod
    def birthday():
        """
        一个班30人，求至少2个人同一天生日的概率
        :return:
        """
        def get_day_max_num(students, days=365):
            """
            获取同一天生日的的最多学生数
            :param students:
            :param days:
            :return:
            """
            birthday_dict = dict()
            for student in range(students):
                birthday = np.random.randint(1, days + 1)
                birthday_dict[birthday] = birthday_dict.get(birthday, 0) + 1

            return max(birthday_dict.values())

        students = 30
        day_nums = 2
        # 蒙特卡洛模拟
        num = 0
        montecarlo_times = 100000
        for _ in range(montecarlo_times):
            max_num = get_day_max_num(students)
            if max_num >= day_nums:
                num += 1

        print('{}个学生中，{}个学生同一天生日的概率: {}%'.format(students, day_nums, 100 * num / montecarlo_times))




montecarlo = MonteCarlo()
# 水果店
# montecarlo.fruit_shop()
# 同一天生日
montecarlo.birthday()
